package jk.framework.spring.security.authorization;


import jk.framework.spring.security.BaseAccess;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 动态安全数据源
 *
 * @author cuichao
 */
public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {


    private final String anyRequestAccess;

    private final SecurityResourcesService resourcesService;

    private final AntPathMatcher matcher = new AntPathMatcher();

    public DynamicSecurityMetadataSource(SecurityResourcesService resourcesService, String anyRequestAccess) {
        super();
        this.resourcesService = resourcesService;
        this.anyRequestAccess = anyRequestAccess;
    }


    private Collection<SecurityResource> loadSecurityResources() {
        return resourcesService.loadSecurityResources();
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {

        final HttpServletRequest request = ((FilterInvocation) object).getRequest();
        //得到请求的URL
        final String requestUrl = ((FilterInvocation) object).getRequestUrl();
        //动态获取SecurityResources
        Collection<SecurityResource> resources = loadSecurityResources();
        //根据Server期望的URL匹配当前的URL得到相应的权限资源
        SecurityResource securityResource = getMatchSource(requestUrl, resources);
        //获取Source对应的权限
        if (securityResource != null && !CollectionUtils.isEmpty(securityResource.getPermissions())) {
            //适配Spring-Security 内置对象
            return configAttributeAdapt(securityResource.getSecurityStrategy(), securityResource.getPermissions(), securityResource.allowIfEqualGrantedDeniedDecisions());
        }
        //没有从SecurityResourcesService获取到权限信息,按照全局规则发放
        return Collections.singleton(new DynamicSecurityAttribute(anyRequestAccess));
    }


    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }

    /**
     * 获取和request-url匹配的SecurityResource
     *
     * @param url
     * @param resources
     * @return
     */
    private SecurityResource getMatchSource(String url, Collection<SecurityResource> resources) {
        if(CollectionUtils.isEmpty(resources)){
            return null;
        }

        for (SecurityResource resource : resources) {
            if (matcher.match(resource.getResource(), url)) {
                return resource;
            }
        }
        return null;

    }

    /**
     * SecurityResource 适配 ConfigAttribute
     *
     * @param strategy
     * @param resources
     * @return
     */
    private Collection<ConfigAttribute> configAttributeAdapt(String strategy, Collection<String> resources, boolean allowIfEqualGrantedDeniedDecisions) {

        Assert.notNull(resources, "You must supply an array of attribute names");

        List<ConfigAttribute> attributes = new ArrayList<>(resources.size());
        for (String attribute : resources) {
            attributes.add(new DynamicSecurityAttribute(attribute.trim(), strategy, allowIfEqualGrantedDeniedDecisions));
        }
        return attributes;

    }

}
